package com.zhang.authoritycenter.service.impl;


import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhang.authoritycenter.common.mapper.auth.UserBaseMapper;
import com.zhang.authoritycenter.common.model.dao.auth.UserBaseDO;
import com.zhang.authoritycenter.common.model.dao.authority.AuthorityUserOrganizationRelateDO;
import com.zhang.authoritycenter.common.model.dao.authority.AuthorityUserRoleRelateDO;
import com.zhang.authoritycenter.common.model.dto.organization.AddUserReqDTO;
import com.zhang.authoritycenter.common.model.dto.organization.OrganizationQueryReqDTO;
import com.zhang.authoritycenter.common.model.dto.organization.UpdateUserReqDTO;
import com.zhang.authoritycenter.common.model.request.RegisterReqDTO;
import com.zhang.authoritycenter.common.model.serviceimpl.AuthorityUserOrganizationRelateServiceImpl;
import com.zhang.authoritycenter.common.model.serviceimpl.AuthorityUserRoleRelateServiceImpl;
import com.zhang.authoritycenter.common.model.vo.organization.OrganizationUserQueryVO;
import com.zhang.authoritycenter.common.properties.BaseProperties;
import com.zhang.authoritycenter.security.UserUtil;
import com.zhang.authoritycenter.service.IRedisService;
import com.zhang.authoritycenter.service.IUserBaseService;
import com.zhang.infrastructure.api.model.authority.AuthByUserDTO;
import com.zhang.infrastructure.model.KingHoodExceptionUtil;
import com.zhang.infrastructure.model.constant.CommonConstants;
import com.zhang.infrastructure.model.constant.redis.RedisConstant;
import com.zhang.infrastructure.model.token.UserDTO;
import com.zhang.infrastructure.util.IdGenUtil;
import com.zhang.mysql.model.KingPageResult;
import com.zhang.mysql.model.PageResponseVO;
import com.zhang.mysql.model.PageUtil;
import com.zhang.redis.util.RedisManager;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author KingHood
 * @since 2023-12-13
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class UserBaseServiceImpl extends ServiceImpl<UserBaseMapper, UserBaseDO> implements IUserBaseService {

    private final RedisManager redisManager;
    private final IRedisService redisService;
    private final BaseProperties baseProperties;
    private final AuthorityUserRoleRelateServiceImpl userRoleRelateService;
    private final AuthorityUserOrganizationRelateServiceImpl userOrganizationRelateService;

    @Override
    public PageResponseVO<OrganizationUserQueryVO> queryUserPage(OrganizationQueryReqDTO in) {

        Page<OrganizationUserQueryVO> page = this.baseMapper.queryPage(PageUtil.getPage(in, in), in);
        return KingPageResult.getResult(page);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public UserBaseDO register(RegisterReqDTO in) {
        // 检查账号是否已经存在，停用账号也考虑在内
        UserBaseDO one = new LambdaQueryChainWrapper<UserBaseDO>(this.getBaseMapper())
                .eq(UserBaseDO::getUsername, in.getUserName())
                .last("limit 1").one();
        KingHoodExceptionUtil.trueThrows(Objects.nonNull(one), "账号已经存在");

        one = new UserBaseDO();
        one.setId(IdGenUtil.get().nextId());
        one.setUsername(in.getUserName());
        one.setPassword(MD5.create().digestHex16(in.getPassword()));
        one.setStatus(1);
        one.setIsDelete(0);
        one.setCreateTime(new Date());
        this.save(one);

        // 缓存账号信息
        redisService.cacheUser(one.getUsername(),one);

        return one;
    }


    @Override
    public UserDTO checkLogin(String userName, String password) {
        // 查找用户信息
        String key = RedisConstant.USERNAME_PREFIX + userName;
        Object value = redisManager.keyValue().get(key);
        UserBaseDO userBaseDO = null;
        if (value instanceof UserBaseDO) {
            userBaseDO = JSON.parseObject(JSON.toJSONString(value), UserBaseDO.class);
        }
        if (Objects.isNull(userBaseDO)) {
            userBaseDO = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                    .eq(UserBaseDO::getUsername, userName).one();
            KingHoodExceptionUtil.isNull(userBaseDO, "用户不存在");
            redisService.cacheUser(userBaseDO.getUsername(),userBaseDO);
        }
        // 对比数据
        String digestPassword = MD5.create().digestHex16(password);
        KingHoodExceptionUtil.trueThrows(!Objects.equals(userBaseDO.getPassword(), digestPassword), "密码错误");

        UserDTO userDTO = new UserDTO();
        userDTO.setId(userBaseDO.getId());
        userDTO.setUsername(userBaseDO.getUsername());
        return userDTO;
    }

    @Override
    public UserBaseDO addUser(AddUserReqDTO in) {
        Integer count = new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(UserBaseDO::getUsername, in.getUsername())
                .count();
        KingHoodExceptionUtil.trueThrows(count > 0, "账号已经存在");

        UserBaseDO one = new UserBaseDO();
        BeanUtils.copyProperties(in, one);
        Date now = new Date();
        one.setPassword(MD5.create().digestHex16(in.getPassword()));
        one.setCreateTime(now);
        one.setUpdateTime(now);
        one.setCreateUserId(UserUtil.getUserId());
        one.setId(IdGenUtil.get().nextId());
        if(Objects.nonNull(one.getPassword())){
            one.setPassword(MD5.create().digestHex16(one.getPassword()));
        }
        this.save(one);

        if(CollectionUtils.isEmpty(in.getOrganizationIdList())){
            saveUserOrganizationBatch(in.getOrganizationIdList(), one, now);
        }

        if(CollectionUtils.isEmpty(in.getRoleIdList())){
            saveUserRoleBatch(in.getRoleIdList(), one, now);
        }

        log.info("新增用户：{}，操作人：{}", in, UserUtil.getUser());
        redisService.cacheUser(one.getUsername(),one);

        return one;
    }

    private void saveUserOrganizationBatch(List<Long> organizationIdList, UserBaseDO one, Date now) {

        List<AuthorityUserOrganizationRelateDO> userOrganizationRelateDOList = organizationIdList.stream().map(x -> {
            AuthorityUserOrganizationRelateDO r = new AuthorityUserOrganizationRelateDO();
            r.setUserId(one.getId());
            r.setRoleId(x);
            r.setCreateTime(now);
            r.setUpdateTime(now);
            r.setCreateUserId(UserUtil.getUserId());
            r.setId(IdGenUtil.get().nextId());
            return r;
        }).collect(Collectors.toList());

        userOrganizationRelateService.saveBatch(userOrganizationRelateDOList);
    }

    private void saveUserRoleBatch(List<Long> roleIdList, UserBaseDO one, Date now) {

        List<AuthorityUserRoleRelateDO> userRoleRelateDOList = roleIdList.stream().map(x -> {
            AuthorityUserRoleRelateDO r = new AuthorityUserRoleRelateDO();
            r.setUserId(one.getId());
            r.setRoleId(x);
            r.setCreateTime(now);
            r.setUpdateTime(now);
            r.setCreateUserId(UserUtil.getUserId());
            r.setId(IdGenUtil.get().nextId());
            return r;
        }).collect(Collectors.toList());

        userRoleRelateService.saveBatch(userRoleRelateDOList);
    }

    @Override
    public UserBaseDO getUser(Long userId) {
        return this.getById(userId);
    }

    @Override
    public UserBaseDO updateUser(UpdateUserReqDTO in) {
        UserBaseDO one = getUser(in.getId());
        KingHoodExceptionUtil.isNull(one, "用户不存在");

        redisService.removeUser(one.getUsername());

        BeanUtils.copyProperties(in, one);
        Date now = new Date();
        one.setUpdateTime(now);
        one.setUpdateUserId(UserUtil.getUserId());
        if(Objects.nonNull(one.getPassword())){
            one.setPassword(MD5.create().digestHex16(one.getPassword()));
        }
        this.updateById(one);

        new LambdaUpdateChainWrapper<>(userOrganizationRelateService.getBaseMapper())
                .eq(AuthorityUserOrganizationRelateDO::getUserId,one.getId())
                .eq(AuthorityUserOrganizationRelateDO::getIsDelete,CommonConstants.IS_DELETE_N)
                .set(AuthorityUserOrganizationRelateDO::getIsDelete,CommonConstants.IS_DELETE_Y)
                .set(AuthorityUserOrganizationRelateDO::getUpdateTime,now)
                .set(AuthorityUserOrganizationRelateDO::getUpdateUserId,UserUtil.getUserId())
                .update();
        if(CollectionUtils.isEmpty(in.getOrganizationIdList())){
            saveUserOrganizationBatch(in.getOrganizationIdList(), one, now);
        }

        new LambdaUpdateChainWrapper<>(userRoleRelateService.getBaseMapper())
                .eq(AuthorityUserRoleRelateDO::getUserId,one.getId())
                .eq(AuthorityUserRoleRelateDO::getIsDelete,CommonConstants.IS_DELETE_N)
                .set(AuthorityUserRoleRelateDO::getIsDelete,CommonConstants.IS_DELETE_Y)
                .set(AuthorityUserRoleRelateDO::getUpdateTime,now)
                .set(AuthorityUserRoleRelateDO::getUpdateUserId,UserUtil.getUserId())
                .update();
        if(CollectionUtils.isEmpty(in.getRoleIdList())){
            saveUserRoleBatch(in.getRoleIdList(), one, now);
        }

        log.info("修改api：{}，操作人：{}", in, UserUtil.getUser());
        return one;
    }

    @Override
    public Boolean deleteUser(List<Long> idList) {
        KingHoodExceptionUtil.isEmpty(idList, "请选择要删除的人员");

        UserDTO user = UserUtil.getUser();
        boolean update = new LambdaUpdateChainWrapper<>(this.getBaseMapper())
                .in(UserBaseDO::getId, idList)
                .set(UserBaseDO::getIsDelete, CommonConstants.IS_DELETE_Y)
                .set(UserBaseDO::getUpdateUserId, UserUtil.getUserId())
                .set(UserBaseDO::getUpdateTime, new Date())
                .update();

        log.info("删除人员：{}，结果：{}，操作人：{}", idList, update, user);

        // 删除人员等token自动过期，如果需要及时性，可以通过用户id记录，在登录token校验的地方做一次用户id的校验
        return update;
    }

    @Override
    public List<UserBaseDO> getList(String name) {

        return new LambdaQueryChainWrapper<>(this.getBaseMapper())
                .eq(StringUtils.isNotBlank(name), UserBaseDO::getUsername, name)
                .eq(UserBaseDO::getIsDelete, CommonConstants.IS_DELETE_N)
                .eq(UserBaseDO::getStatus, CommonConstants.ENABLE)
                .orderByAsc(UserBaseDO::getCreateTime)
                .list();
    }

    @Override
    public AuthByUserDTO getAuth(Long userId) {
        return this.getBaseMapper().getAuth(userId);
    }
}
